package libnetdb.dm.assoc.base;
import java.util.*;

/**
 * In association rule mining, the rules are generated from the
 * large itemsets. In fact, we will build a lattice structure in
 * order to generate the rules efficiently. This lattice structure
 * is named <code>RuleSet</code> in our implementation. And <code>
 * RuleSetBuilder</code> is used to build such a lattic structure
 * from the litemsets. One should build an <code>RuleSet<code> in
 * the following way:
 * <ol>
 *    <li> Reset the rule set builder by specifing the support and
 *         number of transactions. Note that the support specified
 *         here is named the intrinsic support of the rule set. One
 *         cannot generate rules with lower support in that rule
 *         set.
 *    <li> Repeatly call the function <code>addLitemset()</code>
 *         to add the litemsets.
 *    <li> Create the rule set by calling the function <code>
 *         getRuleSet()</code>.
 *    <li> Repeat the above steps if more rule sets are need to
 *         be built.
 * </ol>
 *
 * @author Cheng-Ru Lin
 * @version 1.0
 */
public class RuleSetBuilder {
    private HashMap map = new HashMap();
    private int tranx_numb = 0;
    private double support = 0;
    private int limit = 0;

    /**
     * Constructs a new allocated rule set builder.
     */
    public RuleSetBuilder(){
    }

    private void makeChildLink(LitemsetNode node){
        Litemset litemset = node.getLitemset();
        if(litemset.ids.length==0) return;
        Itemset itemset = new Itemset(new int[litemset.ids.length-1]);
        for(int i=0;i<itemset.ids.length;i++)
            itemset.ids[i] = litemset.ids[i+1];
        for(int i=0;i<itemset.ids.length;i++){
            node.addChild((LitemsetNode) map.get(itemset));
            itemset.ids[i] = litemset.ids[i];
        }
        node.addChild((LitemsetNode) map.get(itemset));
    }

    /**
     * Resets the current builder. This function should be called
     * at the beginning of building a new rule set. Note that
     * the value of support set here should be no lower than the
     * value of supprt set in the mining process.
     *
     * @param tranx_numb the number of transaction
     * @param support the value of support
     */
    public void reset(int tranx_numb, double support){
        this.tranx_numb = tranx_numb;
        this.support = support;
        this.limit = (int) Math.ceil(tranx_numb * support);
    }

    /**
     * Adds the large itemset into the built rule set.
     *
     * @param litemset the large itemset to be added
     */
    public void addLitemset(Litemset litemset){
        map.put(litemset, new LitemsetNode(litemset));
        if(litemset.ids.length==0) tranx_numb = litemset.count;
    }

    /**
     * Gets the rule set which is currently building by this builder.
     * After calling this function, this builder will be reset with
     * the currently value of support and number of transactions.
     * Therefore, this builder is ready to build next rule set.
     *
     * @param confidence the threshold of confidence of the rule set
     * @return the built rule set
     */
    public RuleSet getRuleSet(){
        for(Iterator it = map.values().iterator();it.hasNext();)
            makeChildLink((LitemsetNode) it.next());
        Map old_map = map;
        map = new HashMap();
        return new RuleSet(tranx_numb, old_map, support);
    }
}